/**********************************************************************
 * File:        arab_classes.cpp
 * Description: Inherited classes with more attributes for arabic writings.
 * Author:      Fuad Jamour
 * Created:     Tue Mar 10 2006
 **********************************************************************/

#include          "mfcpch.h"     //precompiled headers
#include	"arab_classes.h"
#include	"tprintf.h"
#include	"varable.h"
#include          "imgs.h"



ELIST2IZE (PixelWithFeatures)	ELIST2IZE (PixelWithDiffs)	ELIST2IZE (Route)	ELIST2IZE (PolygonalEdge)


//Segmentation parameters
#define		MAX_ROUTE_SLOPE_TO_SEGMENT					1.0
#define		MIN_ROUTE_LENGTH_TO_SEGMENT					10
#define		HALF_WINDOW_WIDTH_SUBTLE_BRANCH				20
#define		MIN_Y_DIFF_TO_CONSIDER_SUBTLE_BRNACH		1
#define		MAX_Y_DIFF_TO_CONSIDER_SUBTLE_BRNACH		HALF_WINDOW_WIDTH_SUBTLE_BRANCH
#define		POLYGONAL_MAX_DIST_TO_STOP					3
#define		MAX_POLY_EDGE_ANGLE_TO_KEEP					2.25
//#define		MIN_X_DIFF_TO_CONSIDER_SUBTLE_BRNACH		3




#define		D00		0.000000
#define		D45		0.785398
#define		D90		1.570796
#define		D135	2.356194
#define		D180	3.141592
#define		D225	3.926990
#define		D270	4.712388
#define		D315	5.497787
#define		D360	6.283185

/**********************************************************************
 * makeThinnedImage
 *
 * Creates a thinned version of the image
 **********************************************************************/
void ARAB_IMAGE::makeThinnedImage(bool keepOrigText) {
	thinned = new IMAGE();
	thinned->create(this->get_xsize(), this->get_ysize(), this->get_bpp());
	copy_sub_image(this, 0, 0, this->get_xsize(), this->get_ysize(), thinned, 0, 0, 0);//Copying the original image
	//mysource->write("step4.tif");
	IMAGELINE line, line2;
	line.init();
	line2.init();
	
	IMAGE  temp_img, mysource;
	
	//Ahmad Sep 17, 2008
	mysource.create(this->get_xsize(), this->get_ysize(), 1);
	copy_sub_image(this,0,0,this->get_xsize(),this->get_ysize(),&mysource ,0,0,1);
	//Ahmad end
	temp_img.create(mysource.get_xsize(), mysource.get_ysize(), mysource.get_bpp());
	copy_sub_image(&mysource,0,0,mysource.get_xsize(),mysource.get_ysize(),&temp_img ,0,0,0);
	
	/*this->write("this.tif");
	mysource.write("mysource.tif");
	temp_img.write("temp.tif");
	*/
	int wctr = 0;
	int hctr = 0;
	int wctrUB = mysource.get_xsize();
	int hctrUB = mysource.get_ysize();
	bool DFlag = FALSE;
	int NT, NZ, PrevPoint;
	int x[9];
	
	//this loop clears temp_img
	for (int j = hctrUB-1; j >=0 ; --j)
	{
		temp_img.get_line(0, j, wctrUB, &line, 0);
		
		for(int s=0;s<=wctrUB;s++)
			line.pixels[s]=0;
			
		temp_img.put_line(0, j, wctrUB, &line, 0);
	}

	//this loop reverses the colors of the image 
	for (int j = hctrUB-1; j >=0 ; --j)
	{
		mysource.get_line(0, j, wctrUB, &line, 0);
		
		for(int s=0;s<=wctrUB;s++)
		{
			if(line.pixels[s]==0)
				line.pixels[s]=1;
			else
				line.pixels[s]=0;
		}

		mysource.put_line(0, j, wctrUB, &line, 0);
	}
	
	while(DFlag == FALSE)			
	{
		DFlag = TRUE;
		wctrUB = mysource.get_xsize();
		hctrUB = mysource.get_ysize();

		// Iteration 1 ------------------------------
		for(hctr = hctrUB - 2; hctr > 0; hctr--)
		{
			for(wctr = wctrUB - 2; wctr > 0 ; wctr--)
			{
				if(mysource.pixel(wctr,hctr))
				{
					/*x[1] = mysource.pixel(wctr+1,hctr);
					x[2] = mysource.pixel(wctr+1,hctr-1);
					x[3] = mysource.pixel( wctr ,hctr-1);
					x[4] = mysource.pixel(wctr-1,hctr-1);
					x[5] = mysource.pixel(wctr-1,hctr);
					x[6] = mysource.pixel(wctr-1,hctr+1);
					x[7] = mysource.pixel( wctr ,hctr+1);
					x[8] = mysource.pixel(wctr+1,hctr+1);*/
					x[1] = mysource.pixel(wctr+1,hctr);
					x[8] = mysource.pixel(wctr+1,hctr-1);
					x[7] = mysource.pixel( wctr ,hctr-1);
					x[6] = mysource.pixel(wctr-1,hctr-1);
					x[5] = mysource.pixel(wctr-1,hctr);
					x[4] = mysource.pixel(wctr-1,hctr+1);
					x[3] = mysource.pixel( wctr ,hctr+1);
					x[2] = mysource.pixel(wctr+1,hctr+1);

					// find number of black neighbors
					NZ = 0;
					for (int i=1; i<9; i++)
						if (x[i])
							NZ++;
					
					// find number of 01 transitions
					NT = 0;
					PrevPoint = x[8];
					for (int i=1; i<9; i++) 
					{
						if (PrevPoint==0 && x[i]!=0)
							NT++;
						PrevPoint = x[i];
					}

					if ((NT <= 2) &&
						(NZ !=1) &&
						((x[1] & x[3] & x[5])==0) &&
						((x[1] & x[3] & x[7])==0) && (NZ !=0))
					{
						if (NT != 2) 
						{
							temp_img.get_line(wctr, hctr, 1, &line, 0);
							line.pixels[0]=1;
							temp_img.put_line(wctr, hctr, 1, &line, 0);
							DFlag = FALSE;
						}
						else 
							if ((((x[1]&x[7])==1) && ((x[2]|x[6])==1) &&
 ((x[3]|x[4]|x[5]|x[8])==0)) ||
							    (((x[1]&x[3])==1) && ((x[4]|x[8])==1) &&
 ((x[2]|x[5]|x[6]|x[7])==0))) 
							{
								temp_img.get_line(wctr, hctr, 1, &line, 0);
								line.pixels[0]=1;
								temp_img.put_line(wctr, hctr, 1, &line, 0);
								DFlag = FALSE;
							}
					}
				} // end if
			}  // end for
		}  // end for
		
		for(hctr = hctrUB - 2; hctr > 0; hctr--)
			for(wctr = wctrUB - 2; wctr > 0 ; wctr--)
				if(temp_img.pixel(wctr,hctr) == 1)
				{
					mysource.get_line(wctr, hctr, 1, &line, 0);
					line.pixels[0]=0;
					mysource.put_line(wctr, hctr, 1, &line, 0);
				}
		
		// Iteration 2 ------------------------------
		for(hctr = hctrUB - 2; hctr > 0; hctr--)
		{
			for(wctr = wctrUB - 2; wctr > 0 ; wctr--)
			{
				if(mysource.pixel(wctr,hctr))
				{
					/*x[1] = mysource.pixel(wctr+1,hctr);
					x[2] = mysource.pixel(wctr+1,hctr-1);
					x[3] = mysource.pixel( wctr ,hctr-1);
					x[4] = mysource.pixel(wctr-1,hctr-1);
					x[5] = mysource.pixel(wctr-1,hctr);
					x[6] = mysource.pixel(wctr-1,hctr+1);
					x[7] = mysource.pixel( wctr ,hctr+1);
					x[8] = mysource.pixel(wctr+1,hctr+1);*/
					x[1] = mysource.pixel(wctr+1,hctr);
					x[8] = mysource.pixel(wctr+1,hctr-1);
					x[7] = mysource.pixel( wctr ,hctr-1);
					x[6] = mysource.pixel(wctr-1,hctr-1);
					x[5] = mysource.pixel(wctr-1,hctr);
					x[4] = mysource.pixel(wctr-1,hctr+1);
					x[3] = mysource.pixel( wctr ,hctr+1);
					x[2] = mysource.pixel(wctr+1,hctr+1);

					// find number of black neighbors
					NZ = 0;
					for (int i=1; i<9; i++)
						if (x[i])
							NZ++;
					
					// find number of 01 transitions
					NT = 0;
					PrevPoint = x[8];
					for (int i=1; i<9; i++) 
					{
						if (PrevPoint==0 && x[i]!=0)
							NT++;
						PrevPoint = x[i];
					}

					if ((NT <= 2) &&
						(NZ !=1) &&
						((x[3] & x[5] & x[7])==0) &&
						((x[5] & x[7] & x[1])==0) && (NZ !=0)) 
					{
							if (NT != 2) 
							{
								temp_img.get_line(wctr, hctr, 1, &line, 0);
								line.pixels[0]=1;
								temp_img.put_line(wctr, hctr, 1, &line, 0);
								DFlag = FALSE;
							}
							else if ((((x[5]&x[3])==1) && ((x[6]|x[2])==1) &&
 ((x[1]|x[4]|x[7]|x[8])==0)) ||
									 (((x[7]&x[5])==1) && ((x[8]|x[4])==1) &&
 ((x[1]|x[2]|x[3]|x[6])==0))) 
							{ //5672
									temp_img.get_line(wctr, hctr, 1, &line, 0);
									line.pixels[0]=1;
									temp_img.put_line(wctr, hctr, 1, &line, 0);
									DFlag = FALSE;
							}
					}
				} // end if
			}  // end for
		}  // end for
		
		for(hctr = hctrUB - 2; hctr > 0; hctr--)
			for(wctr = wctrUB - 2; wctr > 0 ; wctr--)
				if(temp_img.pixel(wctr,hctr) == 1)
				{
					mysource.get_line(wctr, hctr, 1, &line, 0);
					line.pixels[0]=0;
					mysource.put_line(wctr, hctr, 1, &line, 0);
				}
	}
		
		// begin stair case removal
		int index;
		for(hctr = hctrUB - 2; hctr > 0; hctr--)
		{
			for(wctr = wctrUB - 2; wctr > 0; wctr--)
			{
				if(mysource.pixel(wctr,hctr))
				{
					/*x[1] = mysource.pixel(wctr+1,hctr);
					x[2] = mysource.pixel(wctr+1,hctr-1);
					x[3] = mysource.pixel( wctr ,hctr-1);
					x[4] = mysource.pixel(wctr-1,hctr-1);
					x[5] = mysource.pixel(wctr-1,hctr);
					x[6] = mysource.pixel(wctr-1,hctr+1);
					x[7] = mysource.pixel( wctr ,hctr+1);
					x[8] = mysource.pixel(wctr+1,hctr+1);*/
					x[1] = mysource.pixel(wctr+1,hctr);
					x[8] = mysource.pixel(wctr+1,hctr-1);
					x[7] = mysource.pixel( wctr ,hctr-1);
					x[6] = mysource.pixel(wctr-1,hctr-1);
					x[5] = mysource.pixel(wctr-1,hctr);
					x[4] = mysource.pixel(wctr-1,hctr+1);
					x[3] = mysource.pixel( wctr ,hctr+1);
					x[2] = mysource.pixel(wctr+1,hctr+1);

					index = 1*x[1] +2*x[2] +4*x[3] +8*x[4] +16*x[5] +32*x[6] +64*x[7]
 +128*x[8];

					// remove staircase
					if ((index == 5) ||
						(index == 20) ||
						(index == 80) ||
						(index == 65)) 
					{
						mysource.get_line(wctr, hctr, 1, &line, 0);
						line.pixels[0]=0;
						mysource.put_line(wctr, hctr, 1, &line, 0);
					}

					// remove extra points
					if ((x[1]+x[3]+x[5]+x[7]) == 3)
					{
						mysource.get_line(wctr, hctr, 1, &line, 0);
						line.pixels[0]=0;
						mysource.put_line(wctr, hctr, 1, &line, 0);
					}
				} // end if
			}  // end for
		}  // end for
		// end stair case removal

		//this loop reverses back the colors of the image 
		for (int j = hctrUB-1; j >=0 ; --j)
		{
			mysource.get_line(0, j, wctrUB, &line, 0);

			for(int s=0;s<wctrUB;s++)
			{
				if(line.pixels[s]==0)
					line.pixels[s]=1;
				else
					line.pixels[s]=0;
			}

			mysource.put_line(0, j, wctrUB, &line, 0);
		}				
	
		//mysource.write("test_thn6.tif");
		
		
		//Ahmad Sep 17, 2008
		line.pixels[0] = thinned->get_white_level();
		for(hctr = hctrUB - 1; hctr >= 0; hctr--)
			for(wctr = wctrUB - 1; wctr >= 0; wctr--)
				if (mysource.pixel(wctr,hctr) == mysource.get_white_level() &&
					thinned->pixel(wctr,hctr) != thinned->get_white_level())
						thinned->put_line(wctr,hctr,1,&line,0);
		thinnedGreyLevel = !thinned->get_white_level();

		if(keepOrigText) {
			thinnedGreyLevel = 200;	//
			line.pixels[0] = thinnedGreyLevel;
			line2.pixels[0] = !thinned->get_white_level();
			for(int xt = 0; xt < thinned->get_xsize(); xt++) {
				for(int yt = 0; yt < thinned->get_ysize(); yt++) {
					if(thinned->pixel(xt, yt) != thinned->get_white_level())
						thinned->put_column(xt, yt, 1, &line, 0);
					if(this->pixel(xt, yt) != this->get_white_level() && thinned->pixel(xt, yt) != thinnedGreyLevel)
						thinned->put_column(xt, yt, 1, &line2, 0);
				}
			}
		}
}//End of makeThinnedImage


/**********************************************************************
 * findFeaturePoints
 *
 * 
 **********************************************************************/
void ARAB_IMAGE::findFeaturePoints() {
	PixelWithFeatures_IT		features_it = &featurePointsLst;
	PixelWithFeatures_LIST		tmpFeat_LIST;
	PixelWithFeatures_IT		tmpFeat_it = &tmpFeat_LIST;
	featurePointsLst.clear();
	BYTE						N8[8];
	BYTE						tmpFeature;

	//PixelWithDiffs_IT pxDers_it = new PixelWithDiffs_LIST;
	//features_it.add_to_end(new PixelWithFeatures(ICOORD(10, 10), BRANCHPT));

	for(int xt = 0; xt < thinned->get_xsize(); xt++) {			//Extracting simple features, namely, END, BRANCH, CROSS points
		for(int yt = 0; yt < thinned->get_ysize(); yt++) {
			if(thinned->pixel(xt, yt) == thinnedGreyLevel) {	
				getN8(ICOORD(xt, yt), N8, thinned); 
				tmpFeature = findSimpleFeature(N8, thinnedGreyLevel);
				if(tmpFeature != NOT_FEATURE_PT) {
					features_it.add_after_then_move(new PixelWithFeatures(ICOORD(xt, yt), tmpFeature));
				}
			}
		}
	}
	
	features_it.move_to_first();
	for(features_it.mark_cycle_pt(); !features_it.cycled_list(); features_it.forward()) {
		this->putPixel(features_it.data()->coords, features_it.data()->feature);	//Marking the feature point on the image for later work
	}

				
	features_it.move_to_first();
	for(features_it.mark_cycle_pt(); !features_it.cycled_list(); features_it.forward()) {
		if(features_it.data()->feature == BRANCH_PT
		|| features_it.data()->feature == CROSS_PT 
		|| features_it.data()->feature == END_PT) {
			getN8(features_it.data()->coords, N8, thinned);
			int tmpX = features_it.data()->coords.x();//TEST////
			for(int i = 0; i < 8; i++) {		//Analyzing possible continuities with 8 neighbourhood connectivity
				if(N8[i] == thinnedGreyLevel)
					analyzeRoute(features_it.data()->coords, i, &tmpFeat_it, thinned);
			}
		}
	}

	features_it.add_list_after(&tmpFeat_LIST);
	
}//End of findFeaturePoints



/**********************************************************************
 * writeWithFeatures
 *
 * 
 **********************************************************************/
void ARAB_IMAGE::writeWithFeatures() {
	PixelWithFeatures_IT features_it = &featurePointsLst;
	features_it.move_to_first();

	for(features_it.mark_cycle_pt(); !features_it.cycled_list(); features_it.forward()) {
		if(features_it.data()->feature == BRANCH_PT)
			putPixel(features_it.data()->coords, 170);	//BLACK DOT FOR A FEATURE NOW!
		else
			putPixel(features_it.data()->coords, 220);	//BLACK DOT FOR A FEATURE NOW!
	}
	//thinned->write("ThinnedWithFeatures.tif");		//Modify to have the fileName with it
}


/**********************************************************************
 * putPixel
 *
 * it modifies the thinned image now! IMP
 **********************************************************************/
inline void ARAB_IMAGE::putPixel(ICOORD coords, BYTE greyLevel) {
	if(coords.x() < 0 || coords.x() > thinned->get_xsize() || coords.y() < 0 || coords.y() > thinned->get_ysize())
		return;
	IMAGELINE line;
	line.init();
	line.pixels[0] = greyLevel;
	thinned->fast_put_line(coords.x(), coords.y(), 1, &line);
}//End of putPixel

/**********************************************************************
 * putPixelImage
 *
 * it modifies the thinned image now! IMP
 **********************************************************************/
inline void ARAB_IMAGE::putPixelImage(ICOORD coords, BYTE greyLevel) {
	if(coords.x() < 0 || coords.x() > thinned->get_xsize() || coords.y() < 0 || coords.y() > thinned->get_ysize())
		return;
	IMAGELINE line;
	line.init();
	line.pixels[0] = greyLevel;
	this->fast_put_line(coords.x(), coords.y(), 1, &line);
}//End of putPixel



/**********************************************************************
 * analyzeRoute
 *
 * 
 **********************************************************************/
void ARAB_IMAGE::analyzeRoute(ICOORD coords, int dir, PixelWithFeatures_IT* tmpFeat_it, IMAGE* thinned) {
	PixelWithDiffs_LIST			px_Ders_LIST;
	PixelWithDiffs_IT			pxDers_it = &px_Ders_LIST;
	PixelWithDiffs				tmpPixelWithDiffs;
	BYTE						N8[8];
	int							pxCount = 0;
	BYTE						whiteLevel = this->get_white_level();
	bool						N8GotFeature = false;
	int							i = 0;	//general loopcounter


	////TEST::
	int dum1 = coords.x();
	////

	pxDers_it.add_after_then_move(new PixelWithDiffs(coords));
	getDirCoords(dir, coords);


	do {
		int ddd = coords.x();
		pxDers_it.add_after_then_move(new PixelWithDiffs(coords));
		if(thinned->pixel(coords.x(), coords.y()) == thinnedGreyLevel)
			this->putPixel(coords, VISITED_PT);
		getN8(coords, N8, thinned);
		if(N8GotSimpleFeature(N8) && pxCount > 0)
			dir = -1;
		else {
			for(int i = 0; i < 8; i++) {
				if(N8[i] == thinnedGreyLevel) {
					dir = i;
					break;
				}
			}
		}
		getDirCoords(dir, coords);
		pxCount++;
	}while(dir != -1);

	//Adding the last pixel i.e the other feature point in the continuity
	for(int i = 0; i < 8; i++) {
		if(N8[i] == END_PT || N8[i] == BRANCH_PT || N8[i] == CROSS_PT) {
			dir = i;
			break;
		}
	}
	getDirCoords(dir, coords);
	pxDers_it.add_after_then_move(new PixelWithDiffs(coords));


	getRoutDiffs(&pxDers_it);


	findEdges(&px_Ders_LIST, tmpFeat_it);



	////TEST
	FILE* fOut;
	fOut = fopen("testRoutes.txt", "w");	
	
	pxDers_it.move_to_first();
	for(pxDers_it.mark_cycle_pt(); !pxDers_it.cycled_list(); pxDers_it.forward()) {
		PixelWithDiffs tmp = *(pxDers_it.data());
		fprintf(fOut,"%d, %d,  \t%d, %d,  \t%d, %d \n", tmp.coords.x(), (this->get_ysize() - tmp.coords.y()) - 1, tmp.firstDiff.x(), tmp.firstDiff.y(), tmp.scndDiff.x(), tmp.scndDiff.y());
	}	
	
	fclose(fOut);
	////
	px_Ders_LIST.clear();
}


inline void ARAB_IMAGE::getRoutDiffs(PixelWithDiffs_IT* pxDers_it) {
	int	pxCnt = 0;
	int routeLength = pxDers_it->length();

	if(routeLength < 4)
		return;

	int	X1, X2, Y1, Y2;

	pxDers_it->move_to_first();
	pxCnt = 0;
	for(pxDers_it->mark_cycle_pt(); !pxDers_it->cycled_list() && pxCnt < routeLength - 1; pxDers_it->forward()) {
		pxCnt++;
		X1 = pxDers_it->data()->coords.x();
		X2 = pxDers_it->data_relative(1)->coords.x();
		Y1 = pxDers_it->data()->coords.y();
		Y2 = pxDers_it->data_relative(1)->coords.y();

		pxDers_it->data()->firstDiff.set_x(X2 - X1);
		pxDers_it->data()->firstDiff.set_y(Y2 - Y1);
	}

	pxDers_it->move_to_first();
	pxCnt = 0;
	for(pxDers_it->mark_cycle_pt(); !pxDers_it->cycled_list() && pxCnt < routeLength - 2; pxDers_it->forward()) {
		pxCnt++;
		X1 = pxDers_it->data()->firstDiff.x();
		X2 = pxDers_it->data_relative(1)->firstDiff.x();
		Y1 = pxDers_it->data()->firstDiff.y();
		Y2 = pxDers_it->data_relative(1)->firstDiff.y();

		pxDers_it->data()->scndDiff.set_x(X2 - X1);
		pxDers_it->data()->scndDiff.set_y(Y2 - Y1);
	}	
}



inline int ARAB_IMAGE::getRouteLength(ICOORD PT1, ICOORD PT2, PixelWithDiffs_LIST* pxDers_LIST) {
	PixelWithDiffs_IT	pxDers_it = pxDers_LIST;
	int					rtLength = 0;
	bool				traceBack = false;
	ICOORD				firstPixel;
	ICOORD				lastPixel;

	pxDers_it.move_to_first();
	firstPixel = pxDers_it.data()->coords;
	pxDers_it.move_to_last();
	lastPixel = pxDers_it.data()->coords;

	if(PT1 == firstPixel && PT2 == lastPixel)
		return pxDers_it.length();

	if(PT1 == firstPixel && PT2 != lastPixel) {
		pxDers_it.move_to_first();
		while(pxDers_it.data()->coords != PT2) {
			rtLength++;
			pxDers_it.forward();
		}
	}
	else if	(PT2 == firstPixel && PT1 != lastPixel) {
		pxDers_it.move_to_first();
		while(pxDers_it.data()->coords != PT1) {
			rtLength++;
			pxDers_it.forward();
		}
	}
	else if (PT1 == lastPixel && PT2 != firstPixel) {
		pxDers_it.move_to_last();
		while(pxDers_it.data()->coords != PT2) {
			rtLength++;
			pxDers_it.backward();
		}
	}
	else if(PT2 == lastPixel && PT1 != firstPixel) {
		pxDers_it.move_to_last();
		while(pxDers_it.data()->coords != PT1) {
			rtLength++;
			pxDers_it.backward();
		}
	} else {
		pxDers_it.move_to_first();
		while(pxDers_it.data()->coords != PT1)
			pxDers_it.forward();

		while(pxDers_it.data()->coords != PT2) {
			rtLength++;
			pxDers_it.forward();
			if(pxDers_it.at_last()) {
				rtLength = 0;
				traceBack = true;
			}
		}

		if(traceBack) {
			pxDers_it.move_to_first();
			while(pxDers_it.data()->coords != PT1)
				pxDers_it.forward();

			while(pxDers_it.data()->coords != PT2) {
				rtLength++;
				pxDers_it.backward();
			}
		}
	}

	return rtLength;
}


inline void ARAB_IMAGE::findEdges(PixelWithDiffs_LIST* pxDers_LIST, PixelWithFeatures_IT* tmpFeat_it) {
	PixelWithDiffs_IT pxDers_it = pxDers_LIST;
	int			routeLength = pxDers_it.length();
	int			relativeDisp = 0;
	int			MIN_DIST_FROM_END = 3;
	double		maxDistLineCont = 0;
	double		MAX_DIST_LINE_CONT = 2;
	double		TOL_IN_THETA = 0;
	ICOORD		lastPixel;
	ICOORD		E1(0, 0);

	//Fuad::
	//	The thresholds MIN_DIST_FROM_END, MAX_DIST_LINE_CONT, TOL_IN_THETA controls the final edges to be
	//	selected.
	//	MIN_DIST_LINE_CONT should be a function of the morphology of the continuities ()
	//	
	//

	if(routeLength < 5)
		return;

	pxDers_it.move_to_last();
	lastPixel = pxDers_it.data()->coords;

	pxDers_it.move_to_first();
	while(E1 != lastPixel) {
		relativeDisp = 0;
		maxDistLineCont = 0;
		while((maxDistLineCont < MAX_DIST_LINE_CONT) && (E1 != lastPixel)) {
			for(int i = relativeDisp; i > 0; i--) {
				maxDistLineCont = max(maxDistLineCont, findDistLinePt(pxDers_it.data()->coords, E1, pxDers_it.data_relative(i)->coords));
			}
			E1 = pxDers_it.data_relative(relativeDisp)->coords;
			relativeDisp++;
		}
		if(getRouteLength(E1, lastPixel, pxDers_LIST) > MIN_DIST_FROM_END)
			tmpFeat_it->add_after_then_move(new PixelWithFeatures(E1, EDGE_PT));
		while(pxDers_it.data()->coords != E1)
			pxDers_it.forward();
	}



}//End of findEdges

void ARAB_IMAGE::findRoutes() {
	PixelWithFeatures_IT		features_it = &featurePointsLst;
	Route_IT					routes_it = &routeList;
	BYTE						N8[8];
	BYTE						tmpFeature;

	//pxDers_it->set_to_list(tmpRoutePtr->getPixelWithDiffsList());

	routeList.clear();

	findSimpleFeatures();

	features_it.move_to_first();
	for(features_it.mark_cycle_pt(); !features_it.cycled_list(); features_it.forward()) {
		if(features_it.data()->feature == BRANCH_PT
		|| features_it.data()->feature == CROSS_PT 
		|| features_it.data()->feature == END_PT) {
			for(int i = 0; i < 8; i++) {		//Analyzing possible continuities with 8 neighborhood connectivity
				getN8(features_it.data()->coords, N8, thinned);
				if(N8[i] == thinnedGreyLevel) {
					int testt = features_it.data()->coords.x();
					Route*	tmpRoutePtr = new Route();
					getRoute(features_it.data()->coords, i, tmpRoutePtr);
					routes_it.add_after_then_move(tmpRoutePtr);
				}
			}
		}
	}
}


void ARAB_IMAGE::findSimpleFeatures() {
	PixelWithFeatures_IT		features_it = &featurePointsLst;
	featurePointsLst.clear();
	BYTE						N8[8];
	BYTE						tmpFeature;

	for(int xt = 0; xt < thinned->get_xsize(); xt++) {			//Extracting simple features, namely, END, BRANCH, CROSS points
		for(int yt = 0; yt < thinned->get_ysize(); yt++) {
			if(thinned->pixel(xt, yt) == thinnedGreyLevel) {	
				getN8(ICOORD(xt, yt), N8, thinned); 
				tmpFeature = findSimpleFeature(N8, thinnedGreyLevel);
				if(tmpFeature != NOT_FEATURE_PT) {
					features_it.add_after_then_move(new PixelWithFeatures(ICOORD(xt, yt), tmpFeature));
				}
			}
		}
	}
	
	features_it.move_to_first();
	for(features_it.mark_cycle_pt(); !features_it.cycled_list(); features_it.forward()) {
		this->putPixel(features_it.data()->coords, features_it.data()->feature);	//Marking the feature point on the image for later work
	}
}


void ARAB_IMAGE::getRoute(ICOORD coords, int dir, Route* routePtr) {
	PixelWithDiffs_IT*			pxDers_it = new PixelWithDiffs_IT(&(routePtr->coordsList));
	PixelWithDiffs				tmpPixelWithDiffs;
	BYTE						N8[8];
	int							pxCount = 0;
	BYTE						whiteLevel = this->get_white_level();
	bool						N8GotFeature = false;
	int							i = 0;	//general loopcounter


	routePtr->firstPt.coords = coords;
	routePtr->firstPt.feature = thinned->pixel(coords.x(), coords.y());

	////TEST::
	int dum1 = coords.x();
	////

	pxDers_it->add_after_then_move(new PixelWithDiffs(coords));
	getDirCoords(dir, coords);


	do {
		int ddd = coords.x();
		pxDers_it->add_after_then_move(new PixelWithDiffs(coords));
		if(thinned->pixel(coords.x(), coords.y()) == thinnedGreyLevel)
			this->putPixel(coords, VISITED_PT);
		getN8(coords, N8, thinned);
		if(N8GotSimpleFeature(N8) && pxCount > 0)
			dir = -1;
		else {
			for(int i = 0; i < 8; i++) {
				if(N8[i] == thinnedGreyLevel) {
					dir = i;
					break;
				}
			}
		}
		getDirCoords(dir, coords);
		pxCount++;
	}while(dir != -1);

	//Adding the last pixel i.e the other feature point in the continuity
	for(int i = 0; i < 8; i++) {
		if(N8[i] == END_PT || N8[i] == BRANCH_PT || N8[i] == CROSS_PT) {
			dir = i;
			break;
		}
	}
	getDirCoords(dir, coords);
	pxDers_it->add_after_then_move(new PixelWithDiffs(coords));


	getRoutDiffs(pxDers_it);

	routePtr->lastPt.coords = coords;
	routePtr->lastPt.feature = thinned->pixel(coords.x(), coords.y());

	////TEST
	//FILE* fOut;
	//fOut = fopen("testRoutes.txt", "w");	
	//
	//pxDers_it->move_to_first();
	//for(pxDers_it->mark_cycle_pt(); !pxDers_it->cycled_list(); pxDers_it->forward()) {
	//	PixelWithDiffs tmp = *(pxDers_it->data());
	//	fprintf(fOut,"%d, %d,  \t%d, %d,  \t%d, %d \n", tmp.coords.x(), (this->get_ysize() - tmp.coords.y()) - 1, tmp.firstDiff.x(), tmp.firstDiff.y(), tmp.scndDiff.x(), tmp.scndDiff.y());
	//}	
	//
	//fclose(fOut);
	////
}


void ARAB_IMAGE::routeToPolygon(PixelWithDiffs_LIST* pxDers_list, PolygonalEdge_LIST* poly_list, double maxErrorDist) {
	PixelWithDiffs_IT pxDers_it = pxDers_list;
	int			routeLength = pxDers_it.length();
	int			relativeDisp = 0;
	int			MIN_DIST_FROM_END = 3;
	double		maxDistLineCont = 0;
	double		theta1 = 0;
	double		theta2 = 0;
	double		largerTheta = 0;
	double		smallerTheta = 0;
	ICOORD		lastPixel;
	ICOORD		E1(0, 0);
	ICOORD		E1_tmp(0, 0);
	PolygonalEdge_IT poly_it = poly_list;
	int			edgeCnt = 0;
	int			polyLength = 0;
	double		deltaY = 0;
	double		deltaX = 0;
	double		deltaTheta = 0;
	double		relativeDistBackFactor = 0.1;
	int			MAX_BACK = 8;



	//Fuad::
	//	The thresholds MIN_DIST_FROM_END, maxErrorDist, TOL_IN_THETA controls the final edges to be
	//	selected.
	//	MIN_DIST_LINE_CONT should be a function of the morphology of the continuities ()
	//	
	//

	if(routeLength < 10)
		return;

	pxDers_it.move_to_last();
	lastPixel = pxDers_it.data()->coords;

	

	pxDers_it.move_to_first();
	int tstX = pxDers_it.data()->coords.x();
	poly_it.add_after_then_move(new PolygonalEdge(pxDers_it.data()->coords));
	while(E1 != lastPixel) {
		relativeDisp = 0;
		maxDistLineCont = 0;
		while((maxDistLineCont < maxErrorDist) && (E1 != lastPixel)) {
			for(int i = relativeDisp; i > 0; i--) {
				maxDistLineCont = max(maxDistLineCont, findDistLinePt(pxDers_it.data()->coords, E1, pxDers_it.data_relative(i)->coords));
			}
			E1 = pxDers_it.data_relative(relativeDisp)->coords;
			relativeDisp++;
		}
		if(getRouteLength(E1, lastPixel, pxDers_list) > MIN_DIST_FROM_END) {
			E1_tmp = pxDers_it.data_relative
				(relativeDisp - (relativeDistBackFactor * relativeDisp))->coords;
			poly_it.add_after_then_move(new PolygonalEdge(E1));//whic is better, E1 or E1_tmp
		}
		while(pxDers_it.data()->coords != E1)
			pxDers_it.forward();
	}
	poly_it.add_after_then_move(new PolygonalEdge(lastPixel));

	polyLength = poly_it.length();
	poly_it.move_to_first();
	poly_it.data()->angle = 10;
	poly_it.forward();
	edgeCnt++;
	while(edgeCnt++ < polyLength - 1) {
		ICOORD tmpCo = poly_it.data()->coords;
		deltaY = poly_it.data_relative(-1)->coords.y() - poly_it.data()->coords.y();
		deltaX = poly_it.data_relative(-1)->coords.x() - poly_it.data()->coords.x();
		theta1 = atan2(deltaY, deltaX);
		if(theta1 < 0)
			theta1 += (D360);

		deltaY = poly_it.data_relative(1)->coords.y() - poly_it.data()->coords.y();
		deltaX = poly_it.data_relative(1)->coords.x() - poly_it.data()->coords.x();
		theta2 = atan2(deltaY, deltaX);
		if(theta2 < 0)
			theta2 += (D360);
		largerTheta = (theta1 >= theta2 ? theta1 : theta2);
		smallerTheta = (theta1 <= theta2 ? theta1 : theta2);
		deltaTheta = largerTheta - smallerTheta;
		if(deltaTheta > D180) {
			deltaTheta = D360 - deltaTheta;
			poly_it.data()->bisectorAngle = (largerTheta + smallerTheta)/2 + D180;
		}
		else
			poly_it.data()->bisectorAngle = (largerTheta + smallerTheta)/2;

		poly_it.data()->angle = deltaTheta;

		if(poly_it.data()->bisectorAngle > D360)
			poly_it.data()->bisectorAngle -= D360;

		int stest = poly_it.data()->coords.x();
		poly_it.forward();
	}
	poly_it.data()->angle = 10;

}



void ARAB_IMAGE::detectLoops() {
	Route_IT	route_it = &routeList;
	Route_IT	route_it2 = &routeList;
	Route_IT	route_it3 = &routeList;
	ICOORD		E1_1;
	ICOORD		E1_2;
	ICOORD		E2_1;
	ICOORD		E2_2;
	ICOORD		E3_1;
	ICOORD		E3_2;
	
	route_it.move_to_first();
	for(route_it.mark_cycle_pt(); !route_it.cycled_list(); route_it.forward()) {
		if((route_it.data()->firstPt.feature == BRANCH_PT
		|| route_it.data()->firstPt.feature == CROSS_PT)
		&& (route_it.data()->lastPt.feature == BRANCH_PT
		|| route_it.data()->lastPt.feature == CROSS_PT)) {
				E1_1 = route_it.data()->firstPt.coords;
				E1_2 = route_it.data()->lastPt.coords;
				if(absFJ(E1_1 - E1_2) < 3)
					route_it.data()->isPartOfLoop = true;
				else {
					route_it.data()->isInLoopDetection = true;
					for(route_it2.mark_cycle_pt(); !route_it2.cycled_list(); route_it2.forward()) {
						if((route_it2.data()->firstPt.feature == BRANCH_PT
						|| route_it2.data()->firstPt.feature == CROSS_PT)
						&& (route_it2.data()->lastPt.feature == BRANCH_PT
						|| route_it2.data()->lastPt.feature == CROSS_PT)
						&& !route_it2.data()->isInLoopDetection) {
								route_it2.data()->isInLoopDetection = true;					
								E2_1 = route_it2.data()->firstPt.coords;
								E2_2 = route_it2.data()->lastPt.coords;
								if((absFJ(E1_1 - E2_1) < 3 || absFJ(E1_1 - E2_2) < 3)
								&& (absFJ(E1_2 - E2_1) < 3 || absFJ(E1_2 - E2_2) < 3)) {
										route_it.data()->isPartOfLoop = true;
										route_it2.data()->isPartOfLoop = true;
								}
								else {
									for(route_it3.mark_cycle_pt(); !route_it3.cycled_list(); route_it3.forward()) {
										if((route_it3.data()->firstPt.feature == BRANCH_PT
										|| route_it3.data()->firstPt.feature == CROSS_PT)
										&& (route_it3.data()->lastPt.feature == BRANCH_PT
										|| route_it3.data()->lastPt.feature == CROSS_PT)
										&& !route_it3.data()->isInLoopDetection) {
												route_it3.data()->isInLoopDetection = true;
												E3_1 = route_it3.data()->firstPt.coords;
												E3_2 = route_it3.data()->lastPt.coords;							

												if( (absFJ(E1_1 - E2_1) < 3 && (absFJ(E1_2 - E3_1) < 3 || absFJ(E1_2 - E3_2) < 3) && (absFJ(E2_2 - E3_1) < 3 || absFJ(E2_2 - E3_2) < 3))
												||	(absFJ(E1_2 - E2_2) < 3 && (absFJ(E1_1 - E3_1) < 3 || absFJ(E1_1 - E3_2) < 3) && (absFJ(E2_1 - E3_1) < 3 || absFJ(E2_1 - E3_2) < 3))
												||	(absFJ(E1_1 - E2_2) < 3 && (absFJ(E1_2 - E3_1) < 3 || absFJ(E1_2 - E3_2) < 3) && (absFJ(E2_1 - E3_1) < 3 || absFJ(E2_1 - E3_2) < 3))
												||	(absFJ(E1_2 - E2_1) < 3 && (absFJ(E1_1 - E3_1) < 3 || absFJ(E1_1 - E3_2) < 3) && (absFJ(E2_2 - E3_1) < 3 || absFJ(E2_2 - E3_2) < 3))
												) {
														route_it.data()->isPartOfLoop = true;
														route_it2.data()->isPartOfLoop = true;
														route_it3.data()->isPartOfLoop = true;
												}
												route_it3.data()->isInLoopDetection = false;
										}
									}
									route_it2.data()->isInLoopDetection = false;
								}
						}
					}
					route_it.data()->isInLoopDetection = false;
				}
		}
	}


	//FUAD:: TEST:: marking the loops
	/*PixelWithDiffs_IT	pxDers_it;
	route_it.move_to_first();
	while(!route_it.at_last()) {
		if(route_it.data()->isPartOfLoop) {
			pxDers_it.set_to_list(route_it.data()->getPixelWithDiffsList());
			for(pxDers_it.mark_cycle_pt(); !pxDers_it.cycled_list(); pxDers_it.forward()) {
				this->putPixel(pxDers_it.data()->coords, 220);
			}
		}
		route_it.forward();
	}*/
	////
}

void ARAB_IMAGE::findEdgeFeatures() {
	PixelWithFeatures_IT	features_it = &featurePointsLst;
	PolygonalEdge_LIST		poly_list;
	PolygonalEdge_IT		poly_it = &poly_list;
	Route_IT				route_it = &routeList;
	double					MAX_ANGLE = 2.3;
	double					MAX_DIST = 3.25;
	bool					isEdgePt = false;


#ifdef MAX_POLY_EDGE_ANGLE_TO_KEEP
	MAX_ANGLE = MAX_POLY_EDGE_ANGLE_TO_KEEP;
#endif

#ifdef POLYGONAL_MAX_DIST_TO_STOP
	MAX_DIST = POLYGONAL_MAX_DIST_TO_STOP;
#endif

	features_it.move_to_last();


	route_it.move_to_last();
	do {
		route_it.forward();
		if(!(route_it.data()->isPartOfLoop)) {
			isEdgePt = false;
			routeToPolygon(route_it.data()->getPixelWithDiffsList(), &poly_list, MAX_DIST);
			poly_it.move_to_first();
			for(poly_it.mark_cycle_pt(); !poly_it.cycled_list() && !isEdgePt; poly_it.forward()) {
				int sscc = route_it.data()->firstPt.coords.x();
				int xxc1 = poly_it.data()->coords.x();
				double bsangl1 = poly_it.data()->bisectorAngle;
				double bbangll = poly_it.data()->angle;
				int dum = 33;
				if(poly_it.data()->angle < MAX_ANGLE
				//|| !(isAnglesEqual(poly_it.data()->bisectorAngle, D90, 0.25))//we need local minimas
				) {
					
					PixelWithFeatures*	pxWthFeatsPtr = new PixelWithFeatures(poly_it.data()->coords, EDGE_PT, poly_it.data()->bisectorAngle);
					int xxc = poly_it.data()->coords.x();
					double bsangl = poly_it.data()->bisectorAngle;
					//features_it.add_after_then_move(pxWthFeatsPtr);
					if(!(isAnglesEqual(poly_it.data()->bisectorAngle, D90, 0.25))) {
						isEdgePt = true;
						splitRoute(&route_it, *pxWthFeatsPtr);
						features_it.add_after_then_move(pxWthFeatsPtr);
					}
				}
			}
			poly_list.clear();
		}
	} while(!route_it.at_last());
	
}


void ARAB_IMAGE::findSubtleBranchFeatures() {
	PixelWithFeatures_IT	features_it = &featurePointsLst;
	Route_IT				route_it = &routeList;
	PixelWithDiffs_IT*		pxDers_it = new PixelWithDiffs_IT;
	bool					isSubtleBranch = false;
	bool					dontMark = false;
	int						routeLength = 0;
	int						relativeDisp = 0;
	int						currentY = 0, currentX = 0;
	int						prevY = 0, prevX = 0;
	int						nextY = 0, nextX = 0;
	int						pxCnt = 0;
	int						lengthOfStraightness = 0;
	int						pxCntBelowCandidateSBranch = 0;
	int						pxCntAboveCandidateSBranch = 0;
	int						i = 0, j = 0;	//general purpose
	int						MIN_Y_DIFF = 0;
	int						MAX_Y_DIFF = 0;
	int						MIN_X_DIFF = 0;
	int						xT = 20;


#ifdef MIN_Y_DIFF_TO_CONSIDER_SUBTLE_BRNACH
	MIN_Y_DIFF = MIN_Y_DIFF_TO_CONSIDER_SUBTLE_BRNACH;
#endif

#ifdef MAX_Y_DIFF_TO_CONSIDER_SUBTLE_BRNACH
	MAX_Y_DIFF = MAX_Y_DIFF_TO_CONSIDER_SUBTLE_BRNACH;
#endif

#ifdef HALF_WINDOW_WIDTH_SUBTLE_BRANCH
	xT = HALF_WINDOW_WIDTH_SUBTLE_BRANCH;
#endif

#ifdef MIN_X_DIFF_TO_CONSIDER_SUBTLE_BRNACH
	MIN_X_DIFF = MIN_X_DIFF_TO_CONSIDER_SUBTLE_BRNACH;
#endif




	features_it.move_to_last();

	route_it.move_to_last();
	do {
		route_it.forward();
		if(!(route_it.data()->isPartOfLoop)) {
			isSubtleBranch = false;
			dontMark = false;
			int testt1 = route_it.data()->firstPt.coords.x();
			pxDers_it->set_to_list(route_it.data()->getPixelWithDiffsList());
			routeLength = pxDers_it->length();
			pxDers_it->move_to_first();
			pxCnt = 0;
			while(!pxDers_it->at_last() && !isSubtleBranch) {
				//TEST
				int dum1 = pxDers_it->data()->coords.x();
				////
				pxCnt++;
				currentY = pxDers_it->data()->coords.y();
				currentX = pxDers_it->data()->coords.x();
				prevY = currentY;
				nextY = currentY;
				prevX = currentX;
				nextX = currentX;

				relativeDisp = -1;
				while(relativeDisp > -xT && (relativeDisp + pxCnt > 0)
				&& pxDers_it->data_relative(relativeDisp)->coords.y() <= prevY
				&& pxDers_it->data_relative(relativeDisp)->coords.x() <= prevX){
					if(pxDers_it->data_relative(relativeDisp)->coords.x() > prevX)
						dontMark = true;
					prevY = pxDers_it->data_relative(relativeDisp)->coords.y();
					prevX = pxDers_it->data_relative(relativeDisp)->coords.x();
					relativeDisp--;
				}
				relativeDisp = 1;
				while(relativeDisp < xT && (relativeDisp + pxCnt < routeLength) 
				&& pxDers_it->data_relative(relativeDisp)->coords.y() <= nextY
				&& pxDers_it->data_relative(relativeDisp)->coords.x() >= nextX){
					if(pxDers_it->data_relative(relativeDisp)->coords.x() < nextX)
						dontMark = true;
					nextY = pxDers_it->data_relative(relativeDisp)->coords.y();
					nextX = pxDers_it->data_relative(relativeDisp)->coords.x();
					relativeDisp++;
				}

				if((currentY  - prevY > MIN_Y_DIFF) 
				&& (currentY  - prevY < MAX_Y_DIFF) 
				&& (currentY  - nextY > MIN_Y_DIFF) 
				&& (currentY  - nextY < MAX_Y_DIFF)
				&& !dontMark
				&& abs(prevY - prevX) < 5) {
					pxCntBelowCandidateSBranch = 0;
					//while(this->pixel(

					isSubtleBranch = true;
					lengthOfStraightness = 0;
					while(pxDers_it->data()->coords.y() == currentY && !pxDers_it->at_last()) {
						pxDers_it->forward();
						pxCnt++;
						lengthOfStraightness++;
					}
				}

				if(isSubtleBranch) {
					PixelWithFeatures*	pxWthFeatsPtr = new PixelWithFeatures(pxDers_it->data_relative(-(lengthOfStraightness/2 + 1))->coords, BRANCH_PT);
					features_it.add_after_then_move(pxWthFeatsPtr);
					for(int i = 0; i < xT - lengthOfStraightness; i++) {
						if(!pxDers_it->at_last()) {
							pxDers_it->forward();
							pxCnt++;
						}
					}
					splitRoute(&route_it,*pxWthFeatsPtr);
				}

				if(!pxDers_it->at_last() && !isSubtleBranch)
					pxDers_it->forward();
			}
		}
	} while(!route_it.at_last());
}


void ARAB_IMAGE::splitRoute(Route_IT* route_it_Ptr, PixelWithFeatures PT1) {
	Route*				route1Ptr = new Route();
	PixelWithDiffs_IT	pxDers_it = route_it_Ptr->data()->getPixelWithDiffsList();
	PixelWithDiffs_IT	pxDers_it1 = route1Ptr->getPixelWithDiffsList();
	int					MIN_LENGTH_TO_CONSIDER = 10;
	int					MIN_DELTA_Y = 10;//to tell how horizontal the route is

	route1Ptr->firstPt = route_it_Ptr->data()->firstPt;
	route1Ptr->lastPt = PT1;
	route_it_Ptr->data()->firstPt = PT1;

	pxDers_it.move_to_first();
	while(pxDers_it.data()->coords != PT1.coords) {
		ICOORD tmp = pxDers_it.data()->coords;
		pxDers_it1.add_after_then_move(pxDers_it.extract());
		pxDers_it.forward();
	}
	pxDers_it1.add_after_then_move(new PixelWithDiffs(pxDers_it.data()->coords));

	route_it_Ptr->add_before_then_move(route1Ptr);
}


void ARAB_IMAGE::findSegmentationPoints() {
	Route_IT			route_it = &routeList;
	PixelWithDiffs_IT	pxDers_it;
	PixelWithFeatures	PT1;			//left end of the current Route
	PixelWithFeatures	PT2;			//right end of the current Route
	PixelWithFeatures	PT1_prev;		//point	information of the Route to the left of the current route
	PixelWithFeatures	PT2_prev;		
	PixelWithFeatures	PT1_next;		//point information if the Route to the right of the current route
	PixelWithFeatures	PT2_next;
	ICOORDELT_IT		segPts_it = &segmentationCoordsList;
	ICOORD				cutPos;
	bool				routeGotCutPt = false;
	double				slope = 0;

	double				MAX_SLOPE = 0.7;
	int					MIN_LENGTH_TO_CONSIDER = 10;

#ifdef MAX_ROUTE_SLOPE_TO_SEGMENT
	MAX_SLOPE = MAX_ROUTE_SLOPE_TO_SEGMENT;
#endif

#ifdef MIN_ROUTE_LENGTH_TO_SEGMENT
	MIN_LENGTH_TO_CONSIDER = MIN_ROUTE_LENGTH_TO_SEGMENT;
#endif


	

	segmentationCoordsList.clear();
	

	route_it.move_to_first();

	for(route_it.mark_cycle_pt(); !route_it.cycled_list(); route_it.forward()) {
		if(!route_it.data()->isPartOfLoop) {
			routeGotCutPt = false;
			int rtXX = route_it.data()->firstPt.coords.x();
			pxDers_it.set_to_list(route_it.data()->getPixelWithDiffsList());
			if(pxDers_it.length() > MIN_LENGTH_TO_CONSIDER) {
				PT1_prev = route_it.data_relative(-1)->firstPt.coords.x() < route_it.data_relative(-1)->lastPt.coords.x() ? route_it.data_relative(-1)->firstPt : route_it.data_relative(-1)->lastPt;//left
				PT2_prev = route_it.data_relative(-1)->firstPt.coords.x() >= route_it.data_relative(-1)->lastPt.coords.x() ? route_it.data_relative(-1)->firstPt : route_it.data_relative(-1)->lastPt;//right
				PT1_next = route_it.data_relative(1)->firstPt.coords.x() < route_it.data_relative(1)->lastPt.coords.x() ? route_it.data_relative(1)->firstPt : route_it.data_relative(1)->lastPt;//left
				PT2_next = route_it.data_relative(1)->firstPt.coords.x() >= route_it.data_relative(1)->lastPt.coords.x() ? route_it.data_relative(1)->firstPt : route_it.data_relative(1)->lastPt;//right
				PT1 = route_it.data()->firstPt.coords.x() < route_it.data()->lastPt.coords.x() ? route_it.data()->firstPt : route_it.data()->lastPt;//left
				PT2 = route_it.data()->firstPt.coords.x() >= route_it.data()->lastPt.coords.x() ? route_it.data()->firstPt : route_it.data()->lastPt;//right
				if(abs(double(PT1.coords.x() - PT2.coords.x())) == 0.0)
					slope = 2;//if the Route is vertical use a slope larger than MAX_SLOPE to ignore this Route
				else
					slope = abs(double(PT1.coords.y() - PT2.coords.y()))/abs(double(PT1.coords.x() - PT2.coords.x()));
				//if(slope < MAX_SLOPE) {
					if(PT2.feature == EDGE_PT) {	//starting with PT2 feature
						if(PT1.feature == EDGE_PT) {
							//further constraints are put below; the function isAnglesEqual(angle1, angle2, tolerance) returns ture if 
							//angle1 is within +or- tolerance from angle2. ALL IN RADIANS
							//e.g. angle1 = 2.443(140 degree) angle2 = D135(defined at the beginning of the file)
							//tolerance = .35(20 degree) the function will return true
							if(isAnglesEqual(PT2.angle, D135, 0.35) && isAnglesEqual(PT1.angle, D315, 0.35)) {
								if(slope < MAX_SLOPE)
									routeGotCutPt = true;
							}
							if(isAnglesEqual(PT2.angle, D135, 0.35) && isAnglesEqual(PT1.angle, D45, 0.35)) {
								if(route_it.data_relative(1)->coordsList.length() < 20 && (PT2_next.feature == END_PT || PT1_next.feature == END_PT))//REVISIT
									if(slope < MAX_SLOPE)
										routeGotCutPt = true;
							}
							if(isAnglesEqual(PT2.angle, D180, 0.35) && isAnglesEqual(PT1.angle, D45, 0.35)) {
								if(slope < MAX_SLOPE)
									routeGotCutPt = true;
							}

							if(isAnglesEqual(PT2.angle, D180, 0.35) && isAnglesEqual(PT1.angle, D90, 0.35)) {
								//aj04_037, aj04_093
								if(slope < 2*MAX_SLOPE)
									routeGotCutPt = true;
							}

							if(isAnglesEqual(PT2.angle, D90, 0.35) && isAnglesEqual(PT1.angle, D45, 0.35)) {
								//aj04_077, aj07_052 BRNCH
								if(slope < MAX_SLOPE)
									if(PT1_next.feature == BRANCH_PT)
										routeGotCutPt = true;
							}

						}
						if(PT1.feature == BRANCH_PT) {
							if(slope < MAX_SLOPE)
								routeGotCutPt = true;
						}
					}
					if(PT2.feature == BRANCH_PT){
						if(PT1.feature == EDGE_PT) {
							if(isAnglesEqual(PT1.angle, D45, 0.35))
								if(slope < MAX_SLOPE)
									routeGotCutPt = true;
						}
						if(PT1.feature == BRANCH_PT) {
							if(slope < MAX_SLOPE)
								routeGotCutPt = true;
						}
					}
					if(PT2.feature == END_PT){
						if(PT1.feature == EDGE_PT) {
							if(isAnglesEqual(PT1.angle, D315, 0.35) || isAnglesEqual(PT1.angle, D45, 0.35))
								if(slope < MAX_SLOPE)
									routeGotCutPt = true;
						}
					}


				//}
			}
			if(routeGotCutPt) {
				//the function findCutPosition returns true always(for now) and detects the segmentation point as the middle 
				//point of the Route. I'll modify it so that it becomes a filter stage; returns false if the 
				//detected segmentation point is far from the baseline or the segmentation point passes a loop
				//This filtering stage adds flexibility in choosing the segmentation rules
				if(findCutPosition(route_it.data(), &cutPos)) {
					segPts_it.add_after_then_move(new ICOORDELT(cutPos));
				}
			}
		}

	}

	//TEST
	segPts_it.move_to_first();
	while(!segPts_it.at_last()) {
		int xx = segPts_it.data()->x();
		int yy = segPts_it.data()->y();
		segPts_it.forward();
	}
	////



}

bool ARAB_IMAGE::findCutPosition(Route* routePtr, ICOORD* cutPositionPtr) {
	PixelWithDiffs_IT		pxDers_it = routePtr->getPixelWithDiffsList();
	int						routeLength = pxDers_it.length();
	int						pxCnt = 0;
	int						MAX_BL = BaseLine + (this->get_ysize()- 40)/4;
	int						MIN_BL = BaseLine - (this->get_ysize() - 40)/4;

	pxDers_it.move_to_first();
	while(pxCnt++ < routeLength/2)
		pxDers_it.forward();

	cutPositionPtr->set_x(pxDers_it.data()->coords.x());
	cutPositionPtr->set_y(pxDers_it.data()->coords.y());

	if(cutPositionPtr->y() > MAX_BL || cutPositionPtr->y() < MIN_BL)
		return false;

	return true;
}



void ARAB_IMAGE::markSegPointsOnImage() {
	ICOORDELT_IT	coords_it = &segmentationCoordsList;
	int				dirOfCut = 0;//1:Vertical     2:-fourtyFive      3:fourtyFive        4:Horizontal
	int				cnt = 0;
	int				xCut = 0;
	int				yCut = 0;
	int				imgX = get_xsize();
	int				imgY = get_ysize();
	int				xt = 0;
	int				yt = 0;
	BYTE			WHITE = get_white_level();


	coords_it.move_to_first();
	for(coords_it.mark_cycle_pt(); !coords_it.cycled_list(); coords_it.forward()) {
		xCut = coords_it.data()->x();
		yCut = coords_it.data()->y();

		xt = xCut;
		yt = yCut;

		cnt = 0;
		while(pixel(xt, yt) != WHITE && cnt < 10) {
			yt++;
			cnt++;
		}
		if(cnt < 10)
			dirOfCut = 1;
		else {
			cnt = 0;
			while(pixel(xt, yt) != WHITE && cnt < 15) {
				yt++;
				xt--;
				cnt++;
			}
			if(cnt < 15)
				dirOfCut = 2;
			else {
				cnt = 0;
				while(pixel(xt, yt) != WHITE && cnt < 15) {
					yt++;
					xt++;
					cnt++;
				}
				if(cnt < 15)
					dirOfCut = 3;
				else {
					cnt = 0;
					while(pixel(xt, yt) != WHITE && cnt < 5) {
						xt++;
						cnt++;
					}
					if(cnt < 5)
						dirOfCut = 4;
				}
			}
		}
	
		xt = xCut;
		yt = yCut;
		switch(dirOfCut) {
		case 1:
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt, yt++), WHITE);
			}
			xt = xCut;
			yt = yCut - 1;
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt, yt--), WHITE);
			}
			break;
		case 2:
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt--, yt++), WHITE);
			}
			xt = xCut + 1;
			yt = yCut - 1;
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt++, yt--), WHITE);
			}
			break;
		case 3:
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt++, yt++), WHITE);
			}
			xt = xCut - 1;
			yt = yCut - 1;
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt--, yt--), WHITE);
			}
			break;
		case 4:
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt++, yt), WHITE);
			}
			xt = xCut - 1;
			yt = yCut;
			while(pixel(xt, yt) != WHITE) {
				putPixelImage(ICOORD(xt--, yt), WHITE);
			}
			break;
		}
	}




}






void ARAB_IMAGE::findBisectorAngles() {
	
}